import React, { memo, useState, useEffect, useContext, useCallback, createContext } from 'react';
import type { PropsWithChildren } from 'react';
import type { Props, Callback } from './interface';

const DarkModeContext = createContext<null | boolean>(null);
const dark = window.matchMedia('(prefers-color-scheme: dark)');

/**
 * 检测深色模式的状态，可传入回调函数
 */
export function useDarkMode(callback: Callback = () => {}) {
  // 是否为深色模式
  const [isDarkMode, setIsDarkMode] = useState(dark?.matches ?? false);
  useEffect(() => {
    callback(isDarkMode);
    const cb = (e: MediaQueryListEvent) => {
      const isDark = e?.matches ?? false;
      callback(isDark);
      setIsDarkMode(isDark);
    };
    dark.addEventListener('change', cb);
    return () => dark.removeEventListener('change', cb);
  }, [callback]);
  return isDarkMode;
}

/**
 * 检测深色模式，并在 `body` 上做个标记，需要搭配 `useTheme` 来使用
 */
export const Theme = memo((props: PropsWithChildren<Props>) => {
  const { disable, tagName = 'dark-mode', children } = props || {};
  /** 获取深色模式的状态并打标 */
  const callback = useCallback(
    (isDark: boolean) => {
      try {
        const { body } = document;
        // 给深色模式下的 body 做个标记，使 CSS 可以快速识别，让 CSS 适配逻辑和 JS 保持一致
        isDark ? body.setAttribute(tagName, 'true') : body.removeAttribute(tagName);
      } catch (e) {
        console.error('在 “body” 上打标失败！');
      }
    },
    [tagName],
  );
  /** 是否为深色模式 */
  const isDarkMode = !disable && useDarkMode(callback);
  return <DarkModeContext.Provider value={isDarkMode}>{children}</DarkModeContext.Provider>;
});

/**
 * 检测深色模式的状态，需要搭配 `Theme` 来使用
 */
export function useTheme() {
  /** 是否为深色模式 */
  const isDarkMode = useContext(DarkModeContext);
  // 未搭配 Theme 组件使用，在控制台输出警告
  if (isDarkMode === null) {
    console.error('“useTheme” 需要搭配 “Theme” 组件来使用，请检查是否正确的将 “根组件” 传入 “Theme” 组件中！');
  }
  return isDarkMode ?? false;
}
